#include "include/CMultipartParser.h"
#include <stdlib.h>
#include <fstream>
#include <time.h>
#include <algorithm>
#include <future>

BASELIB_BEGIN_NAMESPACE


const std::string CMultipartParser::boundary_prefix_("------------");
const std::string CMultipartParser::rand_chars_("0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ");

CMultipartParser::CMultipartParser()
{
	int i = 0;
	int len = rand_chars_.size();
	boundary_ = boundary_prefix_;
	while (i < 24)
	{
		int idx = rand() % len;
		boundary_.push_back(rand_chars_[idx]);
		++i;
	}
}

CMultipartParser::~CMultipartParser()
{

}

const std::string &CMultipartParser::genBodyContent()
{
	body_content_.clear();
#ifdef ZMP1107
	int node = 0;
	for (auto &file : files_)
	{
		std::string filename;
		std::string content_type;

		std::ifstream ifile(file.second, std::ios::binary | std::ios::ate);
		std::streamsize size = ifile.tellg();
		ifile.seekg(0, std::ios::beg);
		char *buff = new char[size];
		ifile.read(buff, size);
		ifile.close();
		std::string file_content(buff, size);
		_get_file_name_type(files_[node].second, &filename, &content_type);
		body_content_ += "\r\n--";
		body_content_ += boundary_;
		body_content_ += "\r\nContent-Disposition: form-data; name=\"";
		body_content_ += files_[node].first;
		body_content_ += "\"; filename=\"";
		body_content_ += filename;
		body_content_ += "\"\r\nContent-Type: ";
		body_content_ += content_type;
		body_content_ += "\r\n\r\n";
		body_content_ += file_content;
		node++;
	}
#else
	std::vector<std::future<std::string> > futures;
	for (auto &file : files_)
	{
		std::future<std::string> content_futures = std::async(std::launch::async, [&file]()
		{
			std::ifstream ifile(file.second, std::ios::binary | std::ios::ate);
			std::streamsize size = ifile.tellg();
			ifile.seekg(0, std::ios::beg);
			char *buff = new char[size];
			ifile.read(buff, size);
			ifile.close();
			std::string ret(buff, size);
			delete[] buff;
			return ret;
		});
		futures.push_back(std::move(content_futures));
	}

	for (size_t i = 0; i < files_.size(); ++i)
	{
		std::string filename;
		std::string content_type;
		std::string file_content = futures[i].get();
		_get_file_name_type(files_[i].second, &filename, &content_type);
		body_content_ += "\r\n--";
		body_content_ += boundary_;
		body_content_ += "\r\nContent-Disposition: form-data; name=\"";
		body_content_ += files_[i].first;
		body_content_ += "\"; filename=\"";
		body_content_ += filename;
		body_content_ += "\"\r\nContent-Type: ";
		body_content_ += content_type;
		body_content_ += "\r\n\r\n";
		body_content_ += file_content;
	}
#endif

	for (auto &param : params_)
	{
		body_content_ += "\r\n--";
		body_content_ += boundary_;
		body_content_ += "\r\nContent-Disposition: form-data; name=\"";
		body_content_ += param.first;
		body_content_ += "\"\r\n\r\n";
		body_content_ += param.second;
	}

	body_content_ += "\r\n--";
	body_content_ += boundary_;
	body_content_ += "--\r\n";

	return body_content_;
}

void CMultipartParser::_get_file_name_type(const std::string &file_path, std::string *filename, std::string *content_type)
{
	if (filename == NULL || content_type == NULL) return;

	size_t last_spliter = file_path.find_last_of("/\\");
	*filename = file_path.substr(last_spliter + 1);
	size_t dot_pos = filename->find_last_of(".");
	if (dot_pos == std::string::npos)
	{
		*content_type = "application/octet-stream";
		return;
	}
	std::string ext = filename->substr(dot_pos + 1);
	std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
	if (ext == "jpg" || ext == "jpeg")
	{
		*content_type = "image/jpeg";
		return;
	}
	if (ext == "txt" || ext == "log")
	{
		*content_type = "text/plain";
		return;
	}
	*content_type = "application/octet-stream";
	return;
}


BASELIB_END_NAMESPACE
